package cn.itsuorce.service.impl;

import cn.hutool.http.HttpUtil;
import cn.itsuorce.Configuration.Constant;
import cn.itsuorce.domain.*;
import cn.itsuorce.domain.dto.UserDto;
import cn.itsuorce.mapper.EmployeeMapper;
import cn.itsuorce.mapper.UserMapper;
import cn.itsuorce.mapper.WxUserMapper;
import cn.itsuorce.query.UserQuery;
import cn.itsuorce.service.IUserService;
import cn.itsuorce.utils.*;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
public class UserServiceImpl extends BaseServiceImpl<User, UserQuery> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private WxUserMapper wxUserMapper;


    /**
     * 验证手机号
     *
     * @param type  1表示手机验证码注册 2表示验证码登录
     * @param phone
     * @return
     */
    @Override
    public AjaxResult validatePhone(Integer type, String phone) {
        //先通过手机号查询User
        User user = userMapper.findByPhone(phone);
        //判断
        if (type == 1) {
            //注册时，若查询到的用户非空，就表示手机号已被占用！
            if (user != null) {
                return AjaxResult.me().setSuccess(false).setMsg("手机号已被注册！");
            }
            return AjaxResult.me();
        } else {
            //登录时，若查询到的用户为空，就表示手机号未注册！
            if (user == null) {
                return AjaxResult.me().setSuccess(false).setMsg("手机号未注册！");
            }
            return AjaxResult.me();
        }
    }

    /**
     * 发送短信验证码
     *
     * @param phone
     * @return
     */
    @Override
    public AjaxResult sendMobileCode(String phone) {
        //随机生成一个4位验证码
        String code = StrUtils.getRandomString(4);

        //本次时间毫秒
        long currentTime = System.currentTimeMillis();
        //先从Redis中获取一下，看看能不能获取到
        String value = RedisUtils.INSTANCE.get(phone);
        //value非空
        if (StringUtils.hasText(value)) {
            //上次获取时间毫秒
            long lastTime = Long.valueOf(value.split(":")[1]);

            //判断时间差
            if (currentTime - lastTime <= 60 * 1000) {
                //1分钟内多次获取
                return AjaxResult.me().setSuccess(false).setMsg("您的操作过于频繁！");
            } else if (currentTime - lastTime <= 300 * 1000) {
                //5分钟内多次获取，直接发送上次的验证码，刷新Redis中的过期时间 重新设置为5分钟
                code = value.split(":")[0];
            }
        }

        RedisUtils.INSTANCE.set(phone, code + ":" + currentTime, 300);
        //调用短信平台接口的发送短信方法【内部就是使用Java程序来发送http请求】
        String text = "您的验证码是：" + code + "，五分钟内有效，打死也不要告诉别人哦！";
        //SmsUtils.INSTANCE.send(phone, text);
        System.out.println(text);

        return AjaxResult.me();
    }

    /**
     * 前台用户注册
     *
     * @param phone
     * @return
     */
    @Override
    public AjaxResult checkPhoneNumber(String phone) {
        User user = userMapper.findByPhone(phone);
        if (user != null) {
            return AjaxResult.me().setSuccess(false).setMsg("该手机号已被注册！！");
        }
        return AjaxResult.me();
    }

    /**
     * 提交表单
     *
     * @param userDto
     * @return
     */
    @Override
    public AjaxResult phoneReg(UserDto userDto) {
        //通过手机号从Redis中获取value  【code:时间毫秒】
        String value = RedisUtils.INSTANCE.get(userDto.getPhone());
        if (StringUtils.hasText(value)) {
            //获取Redis中存储的code
            String code = value.split(":")[0];

            //比较Redis中获取的验证码和前端表单提交的验证码
            if (!code.equals(userDto.getVerifyCode())) {
                return AjaxResult.me().setSuccess(false).setMsg("验证码错误！");
            }

            //保存数据
            User user = new User();
            BeanUtils.copyProperties(userDto, user);
            user.setUsername(userDto.getPhone());       //直接使用手机号作为用户名
            user.setSalt(StrUtils.getComplexRandomString(32));  //盐值
            user.setPassword(MD5Utils.encrypByMd5(userDto.getPassword(), user.getSalt()));  //设置加密的密码
            userMapper.save(user);
            return AjaxResult.me();
        }
        return AjaxResult.me().setSuccess(false).setMsg("验证码已过期！");
    }

    /**
     * 用户登录
     *
     * @param userDto
     * @return
     */
    @Override
    public AjaxResult accountLogin(UserDto userDto) {
        if (userDto.getType() == 1) {
            //通过用户名或者手机号或者邮箱查询一个用户对象
            User user = userMapper.findByPhone(userDto.getAccount());
            System.out.println(userDto.getAccount());
            if (user != null) {
                //将前端提交过来的密码进行加密后 再与数据库中查询到的密码进行比较
                String md5Password = MD5Utils.encrypByMd5(userDto.getPassword(), user.getSalt());
                if (user.getPassword().equals(md5Password)) {
                    //生成一个key
                    String key = UUID.randomUUID().toString();
                    //转化为json字符串
                    String loginUserJsonStr = JSON.toJSONString(user);
                    //登录成功了，应该将用户对象保存到Redis中，30分钟过期
                    RedisUtils.INSTANCE.set(key, loginUserJsonStr, 30 * 60);

                    //封装一个Map，将uuid和用户对象一起返回给前端
                    Map<String, String> map = new HashMap<>();
                    map.put("userToken", key);
                    map.put("loginUser", loginUserJsonStr);
                    return AjaxResult.me().setData(map);
                } else {
                    return AjaxResult.me().setSuccess(false).setMsg("密码错误！");
                }
            }
            return AjaxResult.me().setSuccess(false).setMsg("用户名不存在！");
        } else {
            System.out.println(userDto.getAccount());
            //通过用户名或者手机号或者邮箱查询一个员工对象
            Employee employee = employeeMapper.findByPhone(userDto.getAccount());
            System.out.println(employee);
            if (employee != null) {
                //将前端提交过来的密码进行加密后 再与数据库中查询到的密码进行比较
                String md5Password = MD5Utils.encrypByMd5(userDto.getPassword(), "");
                if (employee.getPassword().equals(md5Password)) {
                    return loginSuccess(employee);
                } else {
                    return AjaxResult.me().setSuccess(false).setMsg("密码错误！");
                }
            }
            return AjaxResult.me().setSuccess(false).setMsg("用户名不存在！");
        }

    }

    @Override
    public AjaxResult wechatLogin(String code) {
        /**
         * 利用Java代码发送http请求：通过授权码换取Token
         *  1.可以利用JDK底层的UrlConnection
         *  2.Apache的commons-httpclient
         *  3.hutool糊涂工具类：HttpUtil
         */
        String access_token_url = Constant.ACCESS_TOKEN_URL
                .replace("APPID", Constant.WECHAT_APPID)
                .replace("SECRET", Constant.WECHAT_SECRECT)
                .replace("CODE", code);
        String result = HttpUtil.get(access_token_url);
        //转化为实体类对象
        AccessTokenResult accessTokenResult = JSON.parseObject(result, AccessTokenResult.class);

        //当errorcode和errormsg同时为null，表示成功！
        if(accessTokenResult.getErrcode() == null && accessTokenResult.getErrmsg() == null){
            //通过unionid和openid查询t_wxuser表
            WxUser wxUser = wxUserMapper.findByUnionidAndOpenid(accessTokenResult.getUnionid(), accessTokenResult.getOpenid());
            if(wxUser != null){
                //获取wxUser绑定的User对象
                User user = wxUser.getUser();
                //登录成功的处理
                return loginSuccess(user);
            }
            //返回消息是未绑定，前端判断之后，可以跳转到用户绑定页面
            return AjaxResult.me().setSuccess(false).setMsg("unbind").setData(accessTokenResult);
        }
        return AjaxResult.me().setSuccess(false).setMsg("微信登录失败~");
    }

    /**
     * 微信用户扫码登录后，绑定我们系统的用户（等同于注册）
     * @param userDto
     * @return
     */
    @Override
    @Transactional
    public AjaxResult wechatUserBind(UserDto userDto) {
        //1.验证一下短信验证码是否正确
        //通过手机号从Redis中获取value  【code:时间毫秒】
        String value = RedisUtils.INSTANCE.get(userDto.getPhone());
        if(!StringUtils.hasText(value)) {
            return AjaxResult.me().setSuccess(false).setMsg("验证码已过期！");
        }
        //获取Redis中存储的code
        String code = value.split(":")[0];
        //比较Redis中获取的验证码和前端表单提交的验证码
        if (!code.equals(userDto.getVerifyCode())) {
            return AjaxResult.me().setSuccess(false).setMsg("验证码错误！");
        }

        //2.先通过access_token和openid，获取微信用户的个人信息
        String wechat_userinfo_url = Constant.WECHAT_USERINFO_URL
                .replace("ACCESS_TOKEN", userDto.getAccess_token())
                .replace("OPENID", userDto.getOpenid());
        String userinfoResult = HttpUtil.get(wechat_userinfo_url);

        //3.解析json字符串，封装成实体类对象
        WechatUserinfo wechatUserinfo = JSON.parseObject(userinfoResult, WechatUserinfo.class);

        //4.插入数据到t_user表，返回主键
        if(wechatUserinfo.getErrcode() != null || wechatUserinfo.getErrmsg() != null){
            return AjaxResult.me().setSuccess(false).setMsg("获取微信用户信息失败！");
        }
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        user.setUsername(userDto.getPhone());
        user.setSalt(StrUtils.getComplexRandomString(32));  //盐值
        user.setPassword(MD5Utils.encrypByMd5(userDto.getPassword(), user.getSalt()));  //密码加密
        user.setHeadImg(wechatUserinfo.getHeadimgurl());
        userMapper.save(user);

        //5.插入数据到t_wxuser表
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(wechatUserinfo.getOpenid());
        wxUser.setNickname(wechatUserinfo.getNickname());
        wxUser.setSex(wechatUserinfo.getSex());
        wxUser.setAddress(wechatUserinfo.getCountry() + " " + wechatUserinfo.getProvince() + " " + wechatUserinfo.getCity());
        wxUser.setHeadimgurl(wechatUserinfo.getHeadimgurl());
        wxUser.setUnionid(wechatUserinfo.getUnionid());
        wxUser.setUser_id(user.getId());
        wxUserMapper.save(wxUser);

        //6.返回登录成功的数据
        return loginSuccess(user);
    }

    private AjaxResult loginSuccess(Object user) {
        //生成一个key
        String key = UUID.randomUUID().toString();
        //转化为json字符串
        String loginUserJsonStr = JSON.toJSONString(user);
        //登录成功了，应该将用户对象保存到Redis中，30分钟过期
        RedisUtils.INSTANCE.set(key, loginUserJsonStr, 30 * 60);

        //封装一个Map，将uuid和用户对象一起返回给前端
        Map<String,String> map = new HashMap<>();
        map.put("userToken", key);
        map.put("loginUser", loginUserJsonStr);
        return AjaxResult.me().setData(map);
    }
}
